﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;


namespace ClassLibrary
{
    public class NaturalSelectionTable
    {
        public string path { set; get; }
        public string name { set; get; }

        public int natural_selection_variants_amount { set; get; }
        public Dictionary<NaturalSelectorParametersArea, NaturalSelectionVariant> natural_selection_table = new Dictionary<NaturalSelectorParametersArea, NaturalSelectionVariant>();
        public string path_to_default_natural_selection_link;
        public string path_to_default_reproduction_link;
        public string path_to_phenotype_table;

        /* constructor */
        public NaturalSelectionTable(string path_to_natural_selecton_table)
        {
            path = path_to_natural_selecton_table;

            // open XML file            
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(File.ReadAllText(path_to_natural_selecton_table));            

            // reading natural_selecton_table's attributes
            name = doc.DocumentElement.GetAttribute("Name");
            natural_selection_variants_amount = Convert.ToInt32(doc.DocumentElement.GetAttribute("NaturalSelectionVariantsAmount"));
            path_to_default_natural_selection_link = doc.DocumentElement.GetAttribute("PathToDefualtNaturalSelectionLink");
            path_to_default_reproduction_link = doc.DocumentElement.GetAttribute("PathToDefualtReproductionLink");
            path_to_phenotype_table = doc.DocumentElement.GetAttribute("PathToPhenotypeTable");

            // reading all data about natural selection variants
            if (natural_selection_variants_amount != 0)
            {
                // reading "natural_selection_variant" nodes               
                foreach (XmlNode xml_node in doc.GetElementsByTagName("natural_selection_variant"))
                {
                    int id = Convert.ToInt32(xml_node.Attributes[0].Value);
                    int first_time_step = Convert.ToInt32(xml_node.Attributes[1].Value);
                    int last_time_step = Convert.ToInt32(xml_node.Attributes[2].Value);

                    // checking for "-1" - a flag of maximal value for parameter "last_time_step"
                    last_time_step = (last_time_step == -1) ? int.MaxValue : last_time_step;
                    
                    int amount_of_individuals_lower_bound = Convert.ToInt32(xml_node.Attributes[3].Value);
                    int amount_of_individuals_upper_bound = Convert.ToInt32(xml_node.Attributes[4].Value);

                    // checking for "-1" - a flag of maximal value for parameter "amount_of_individuals_upper_bound"
                    amount_of_individuals_upper_bound = (amount_of_individuals_upper_bound == -1) ? int.MaxValue : amount_of_individuals_upper_bound;                    

                    NaturalSelectorParametersArea natural_selection_parameters_area = new NaturalSelectorParametersArea(id,first_time_step, last_time_step,
                                                                                          amount_of_individuals_lower_bound, amount_of_individuals_upper_bound);

                    string path_to_natural_selection_link = xml_node.Attributes[5].Value;
                    string path_to_reproduction_link = xml_node.Attributes[6].Value;
                    NaturalSelectionVariant natural_selection_variant = new NaturalSelectionVariant(path_to_natural_selection_link,
                                                                                                    path_to_reproduction_link);

                    natural_selection_table.Add(natural_selection_parameters_area, natural_selection_variant);
                }
            }           
        }

        public string getPathToNaturalSelectionLink(NaturalSelectorParametersArea na_se_pa_area)
        {
            if ( natural_selection_table.ContainsKey(na_se_pa_area))
            {
                return natural_selection_table[na_se_pa_area].path_to_natural_selection_link;
            } else
            {
                return path_to_default_natural_selection_link;
            }
        }

        public string getPathToReproductionLink(NaturalSelectorParametersArea na_se_pa_area)
        {
            if (natural_selection_table.ContainsKey(na_se_pa_area))
            {
                return natural_selection_table[na_se_pa_area].path_to_reproduction_link;
            }
            else
            {
                return path_to_default_reproduction_link;
            }
        }
    }


    /*
     * class for storing area on parameters space 
     * for deteriming natural_selecton_link
    */ 
    public class NaturalSelectorParametersArea
    {
        public int id { set; get; }
        public int first_time_step { set; get; }
        public int last_time_step { set; get; }
        public int amount_of_individuals_lower_bound { set; get; }
        public int amount_of_individuals_upper_bound { set; get; }

        /* constructor */
        public NaturalSelectorParametersArea(int i,int fs_tm_step, int ls_tm_step, int amount_ind_lower_bound, int amount_ind_upper_bound)
        {
            id = i;
            first_time_step = fs_tm_step;
            last_time_step = ls_tm_step;
            amount_of_individuals_lower_bound = amount_ind_lower_bound;
            amount_of_individuals_upper_bound = amount_ind_upper_bound;
        }
        public NaturalSelectorParametersArea(int fs_tm_step, int ls_tm_step, int amount_ind_lower_bound, int amount_ind_upper_bound)
        {            
            first_time_step = fs_tm_step;
            last_time_step = ls_tm_step;
            amount_of_individuals_lower_bound = amount_ind_lower_bound;
            amount_of_individuals_upper_bound = amount_ind_upper_bound;
        }
        public bool Equals(NaturalSelectorParametersArea other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;

            bool equals = true;

            equals = equals && (first_time_step <= other.first_time_step);
            equals = equals && (last_time_step >= other.last_time_step);
            equals = equals && (amount_of_individuals_lower_bound <= other.amount_of_individuals_lower_bound);
            equals = equals && (amount_of_individuals_upper_bound >= other.amount_of_individuals_upper_bound);

            return equals;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof(NaturalSelectorParametersArea)) return false;
            return Equals((NaturalSelectorParametersArea)obj);
        }

        public override int GetHashCode()
        {
            return 0;
        }
    }
}

    /*
     * class for storing data about
     * natural selection variant
    */
    public class NaturalSelectionVariant
    {
        public string path_to_natural_selection_link { set; get; }
        public string path_to_reproduction_link { set; get; }

        public NaturalSelectionVariant(string path_to_na_se_li, string path_to_re_li)
        {
            path_to_natural_selection_link = path_to_na_se_li;
            path_to_reproduction_link = path_to_re_li;
        }
    }